/**
 * Contains {@link PathElement}
 */
package logic.pathelements;

import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import logic.connectors.Connector;

/**
 * PathElement
 * @author Alexey Akimov <frinatella@gmail.com>
 */
public abstract class PathElement implements Serializable {
    
    /**
     * 
     */
    private static final long serialVersionUID = 2087148390635177780L;

	/**
     * this element connectors
     */
    protected ArrayList<Connector> connectors;
    
    /**
     * this element id
     */
    protected Integer id;
    
    /**
     * this element connectors count
     */
    protected int connectorsCount;
    
    /**
     * Constructor
     * 
     * Sets this element id and connectors count according to its parameters
     * @param id this element id
     * @param connectorsCount this element connectors count
     */
    public PathElement(Integer id, int connectorsCount) {
        this.id = id;
        this.connectorsCount = connectorsCount;        
        connectors = new ArrayList<Connector>();
    }
    
    /**
     * Connect one of this element connectors to one of the other element connectors
     * @param thisElementConnectorNumber this element connector number
     * @param otherElement other element to be connected to this element by its connectors numbers
     * @param otherElementConnectorNumber other element connector number
     */
    public void connect(int thisElementConnectorNumber, PathElement otherElement, int otherElementConnectorNumber) {
        Connector thisElementConnector = connectors.get(thisElementConnectorNumber);
        Connector otherElementConnector = otherElement.connectors.get(otherElementConnectorNumber);
        thisElementConnector.connectTo(otherElementConnector);
        otherElementConnector.connectTo(thisElementConnector);
    }
    
    /**
     * Disconnect this element and other element connectors from each others
     * @param connectorNumber this interface connector number
     */
    public void disconnect(int connectorNumber) {
        Connector connector = connectors.get(connectorNumber);
        connector.connectedTo().disconnect();
        connector.disconnect();
    }
    
    /**
     * @return costs of this path element
     */
    public abstract double getCosts();
    
    /**
     * Getter
     * @return this element needed connector
     */
    public Connector getConnector(int connectorNumber) {
        return connectors.get(connectorNumber);
    }
    
    /**
     * Getter
     * @return collection of this element connectors
     */
    public ArrayList<Connector> getConnectors() {
        return connectors;
    }
    
    /**
     * Getter
     * @return this element connectors count
     */
    public int getConnectorsCount() {
        return connectorsCount;
    }

    @Override
    public String toString() {
        return "\nClass: " + this.getClass().getName() + "\nid: " + id;
    }
    
    /**
     * Getter
     * @param sourceConnector 
     * @param protocol protocol type
     * @param srcI source ip-address
     * @param destIp destination ip-address
     * @param srcPort source port number
     * @param destPort destination port number
     * @return collection of this element connectors according to route and this element parameters
     */
    public Collection<Connector> getRouteConnectors(Connector sourceConnector, Protocol protocol, InetAddress srcIp,InetAddress destIp, int srcPort, int destPort) {
        ArrayList<Connector> routeConnectors = new ArrayList<Connector>();
        for (Connector connector : connectors) {
            if (connector != sourceConnector) {
                routeConnectors.add(connector);
            }
        }
        return routeConnectors;
    }
       
    
    /** 
     * Getter
     * @return path element id
     */
    public Integer getId() {
        return id;
    }
    
    /**
     * Getter
     * @return path element info
     */
    public abstract String getInfo();
    
    /** 
     * Getter
     * @return Time delay on this path element
     */
    public abstract double getTimeDelay();
}
